/**
 * Copyright (c) 2006, PORTALIER Julien
 * 
 * Licensed under The LGPL License
 * Redistributions of files must retain the above copyright notice.
 * 
 * @package    FeatherCMS
 * @subpackage Javascript
 * @copyright  Copyright (c) 2006, Julien PORTALIER
 * @link       http://portalier.com/feather
 * @license    http://www.opensource.org/licenses/lgpl-license.php The LGPL License
 */

var Calendar = {};
Calendar.Languages = {};

Calendar.Languages.fr_FR = {
	months:             [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre' ],
	weekDays:           [ 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche' ],
	weekDaysShort:      [ 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam', 'dim' ],
	nonWorkingWeekDays: [ 7 ],
	nonWorkingYearDays: [ '1-1', '8-15', '11-11', '12-25' ]
};

Calendar.Languages.en_GB = {
	months:             [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
	weekDays:           [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ],
	weekDaysShort:      [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ],
	nonWorkingWeekDays: [ 7 ],
	nonWorkingYearDays: [  ]
};

Calendar.Base = new Class(
{
	initialize: function(input, options)
	{
		this.options = {
			className:       'calendar',
			buttonClassName: 'calendarButton',
			injectButton:    'Before',
			insert:    'After',
			format:    'Y-m-d h:i:s',
			from:      0,
			to:        0,
			locale:    'fr_FR',
			button:    '/img/icons/calendar.png'
		};
		this.options = Object.extend(this.options, options || {});
		this.weekNumDays   = 7;
		
		this.locale = Calendar.Languages[this.options.locale];
		
		// elements
		this.input = $(input);
		this.button = new Element('a', {href: '#', 'class': this.options.buttonClassName},
			new Element('img', {src: '/img/icons/calendar.png'})
		)['inject' + this.options.injectButton](this.input).addEvent('click', this.onDisplay.bind(this));
	},
	
	getMonthNumDays: function()
	{
		return this.monthNumDays[this.date.getMonth()];
	},
	
	create: function()
	{
		// weekdays
		this.weekdays = new Element('tr', {'class': 'weekdays'});
		for (var wd = 0; wd < this.weekNumDays; wd++) {
			new Element('th', {title: this.locale.weekDays[wd]}, this.locale.weekDaysShort[wd]).injectInside(this.weekdays);
		}
		
		// calendar
		this.calendar = new Element('div', {'class': this.options.className, id: Math.random()},
			new Element('div', {'class': 'content'},
				new Element('div', {'class': 'year-month'},
					new Element('a', {href: '#', 'class': 'previousYear',  title: _('Previous year')}, '<<'), ' ',
					new Element('a', {href: '#', 'class': 'previousMonth', title: _('Previous month')}, '<'), ' ',
					
					new Element('span', {'class': 'date'}), ' ',
					
					new Element('a', {href: '#', 'class': 'nextMonth',     title: _('Next month')}, '>'), ' ',
					new Element('a', {href: '#', 'class': 'nextYear',      title: _('Next year')},  '>>')
				),
				new Element('table')
			)
		).addEvent('click', this.onClick.bind(this));
		
		// set date
		this.date = new Date();
		this.date.setFullYear(this.input.value.slice(0, 4));
		this.date.setMonth(this.input.value.slice(5, 7) - 1);
		this.date.setDate(this.input.value.slice(8, 10));
		this.date.setHours(this.input.value.slice(11, 13));
		this.date.setMinutes(this.input.value.slice(14, 16));
		this.date.setSeconds(this.input.value.slice(17, 19));
	},
	
	update: function()
	{
		var month = this.date.getMonth();
		var year  = this.date.getFullYear();
		
		// date
		$E('.date', this.calendar).setHTML(this.locale.months[month] + ' ' + year);
		
		// days
		days = new Element('table', {summary: 'calendar'});
		this.weekdays.injectInside(days);
		
		// first day of month
		var d = new Date();
		d.setFullYear(year);
		d.setMonth(month);
		d.setDate(0);
		var offset = d.getDay();
		
		var today = new Date();
		
		// each day of month
		var start  = true;
		var day, week = new Element('tr');
		var wd = 0, md = 0;
		
		while(md < this.getMonthNumDays())
		{
			if (wd < this.weekNumDays) {
				wd++;
			}
			else
			{
				// new week
				wd = 1;
				week.injectInside(days);
				week = new Element('tr');
			}
			
			day = new Element('td');
			
			start = (start && wd <= offset);
			if (!start)
			{
				new Element('a', {'href': '#'}, md + 1 + '').injectInside(day);
				
				if (today.getFullYear() == year && today.getMonth() == month && today.getDate() == md + 1) {
					day.addClass('today');
				}
				if (this.locale.nonWorkingWeekDays.test(wd) || this.locale.nonWorkingYearDays.test((this.date.getMonth() + 1) + '-' + (md + 1))) {
					day.addClass('nonWorkingDay');
				}
				
				md++;
			}
			
			day.injectInside(week);
			
		}
		if (week.hasChildNodes()) {
			week.injectInside(days);
		}
		
		$E('table', this.calendar).replaceWith(days);
	},
	
	onClick: function(evt)
	{
		var target = new Event(evt).stop().target();
		
		if (target.isChildOf($E('.year-month', this.calendar)))
		{
			// changed date
			if (target.hasClass('previousYear')) {
				this.date.setFullYear(this.date.getFullYear() - 1);
			}
			else if (target.hasClass('nextYear')) {
				this.date.setFullYear(this.date.getFullYear() + 1);
			}
			else if (target.hasClass('previousMonth')) {
				this.date.setMonth(this.date.getMonth() - 1);
			}
			else if (target.hasClass('nextMonth')) {
				this.date.setMonth(this.date.getMonth() + 1);
			}
			this.update();
		}
		else if (target.isChildOf($E('table', this.calendar)) && target.getTag() == 'a')
		{
			// picked a date
			this.input.value = this.date.getFullYear() + '-' +
				this.__parse(parseInt(this.date.getMonth(), 10) + 1) + '-' +
				this.__parse(target.innerHTML) + ' ' +
				this.__parse(this.date.getHours()) + ':' +
				this.__parse(this.date.getMinutes()) + ':' +
				this.__parse(this.date.getSeconds());
			
			this.destroy();
		}
	},
	
	__parse: function(v)
	{
		return (v >= 10) ? v : '0' + v;
	},
	
	onDisplay: function(evt)
	{
//		new Event(evt).preventDefault();
		new Event(evt).stop();
		
		if (!this.calendar)
		{
			// creation
			this.create();
			this.update();
			
			// position
			/*
			this.calendar.setStyles({
				position: 'absolute',
				top:  this.button.getTop()  + 'px',
				left: this.button.getLeft() + this.button.offsetWidth + 4 + 'px'
			});
			*/
			
			// insert in DOM
			//this.calendar.injectInside(document.body);
			this.calendar.injectAfter(this.button);

			this.input.focus();
		}
		else {
			this.destroy();
		}
		
		if (!this.eventListener)
		{
			// click anywhere to destroy calendar
			$(document.body).addEvent('click', this.destroy.bind(this));
			this.eventListener = true;
		}
	},
	
	destroy: function(evt)
	{
		if (this.calendar)
		{
			this.calendar.remove();
			this.calendar = null;
		}
		//$(document.body).removeEvent('click', this.destroy.bind(this));
	}
});

Calendar.Gregorian = Calendar.Base.extend(
{
	initialize: function(input, options)
	{
		this.weekNumDays  = 7;
		this.monthNumDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
		this.parent(input, options);
	},
	
	getMonthNumDays: function()
	{
		var month = this.date.getMonth();
		var year  = this.date.getFullYear();
		return (month == 1 && year%400 === 0 || (year%100 !== 0 && year%4 === 0)) ?
			29 : this.monthNumDays[month];
	}
});
